#ifndef __TABLE_MODELS__HH__
#define __TABLE_MODELS__HH__

#include <vector>
#include <sstream>
using namespace std;

#include <dyntype/dyntype.h>
#include <QtCore/QAbstractTableModel>

template <class V>
class VectorAdapter {
public:
  virtual ~VectorAdapter() {}
  virtual size_t size() const = 0;
  virtual V* get_at_ptr(size_t index) = 0;
  virtual const V& get_at(size_t index) const = 0;
};

template <class V>
class STLVectorAdapter : public VectorAdapter<V> {
public:
  vector<V>* vs;
  STLVectorAdapter(vector<V>* vs) { this->vs = vs; }
  size_t size() const { return vs->size(); }
  V* get_at_ptr(size_t i) { return &(*vs)[i]; }
  const V& get_at(size_t i) const { return (*vs)[i]; }
};

// ..............................................................

template <class V>
class VectorModel : public QAbstractTableModel
{
public:
  DynType* v_dyntype;
  const VectorAdapter<V>* vs;
  VectorModel(const VectorAdapter<V>* vs);

  // Qt
  int rowCount(const QModelIndex&) const;
  int columnCount(const QModelIndex&) const;
  QVariant data(const QModelIndex& index, int role) const;
  QVariant headerData(int section, Qt::Orientation orientation,int role) const;
};

// ..............................................................

template <class V>
inline
VectorModel<V>::VectorModel(const VectorAdapter<V>* vs) 
{
  this->v_dyntype = get_dyntype<V>();
  this->vs = vs;
}

// Qt
template <class V>
inline
int
VectorModel<V>::rowCount(const QModelIndex&) const 
{
  return vs->size();
}

template <class V>
inline int
VectorModel<V>::columnCount(const QModelIndex&) const 
{
  int ret = 1;
  CompoundDynType* cdt = dynamic_cast<CompoundDynType*>(v_dyntype);
  if (cdt) {
    ret = cdt->get_nof_members();
  }
  return ret;
}

template <class V>
inline QVariant
VectorModel<V>::data(const QModelIndex& index, int role) const
{
  if (!index.isValid()) {
    return QVariant(); 
  }
  if (role != Qt::DisplayRole) {
    return QVariant();
  }
  int row_index = index.row();
  int col_index = index.column();
  
  QVariant ret;
  CompoundDynType* cdt = dynamic_cast<CompoundDynType*>(v_dyntype);
  if (cdt != 0) {
    char buf[1024];
    cdt->snprintf_member(buf, sizeof(buf),
			 col_index,
			 membuf_t((char*)&vs->get_at(row_index), sizeof(V)));
    ret = buf;
  } else {
    ostringstream out;
    v_dyntype->print_obj(out, membuf_t((char*)&vs->get_at(row_index), sizeof(V)));
    ret = out.str().c_str();
  }
  return ret;
}

template <class V>
inline QVariant 
VectorModel<V>::headerData(int section, 
			   Qt::Orientation orientation,int role) const 
{ 
  if (role != Qt::DisplayRole) {
      return QVariant();
  }
    
  QVariant ret;
  if (orientation == Qt::Horizontal) {
    CompoundDynType* cdt = dynamic_cast<CompoundDynType*>(v_dyntype);
    if (cdt != 0) {
      ret = cdt->get_member_name(section).c_str();
    } else {
      ret = "__value__";
    }
  } else if (orientation == Qt::Vertical) {
    char v_buf[256]; memset(v_buf, '\0', sizeof(v_buf));
    sprintf(v_buf, "row%d", section);
    ret = v_buf;
  }
  return ret;
}

#endif
